package com.st.reqandresp;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.*;

/**
 * Created by zhangshuai on 2017/8/30.
 */
public class Request {

    //请求方法
    private String method;

    /**请求资源*/
    private String url;

    private String characterEncoding;

    /** 参数 */
    private Map<String,List<String>> parameterMap;

    private String paramStr;

    private static final String CRLF = "\r\n";
    private static final String BLANK = " ";

    private InputStream inputStream;

    private String requestInfo;

    private String servletPath;

    private Request(){
        method = "";
        url = "";
        parameterMap = new HashMap<>();
        requestInfo = "";
        characterEncoding = "GBK";
    }

    public Request(InputStream inputStream){
        this();
        this.inputStream = inputStream;
        //分析请求头信息,读取到空行为止
        this.parseRequest();
    }

    public Request(Socket client){
        this();
        try{
            this.inputStream = client.getInputStream();
        }catch (Exception e){
            //解析request.getInputStream()发生异常
            e.printStackTrace();
        }
        //分析请求头信息,读取到空行为止
        this.parseRequest();
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getCharacterEncoding() {
        return characterEncoding;
    }

    public void setCharacterEncoding(String characterEncoding) {
        this.characterEncoding = characterEncoding;
        this.parseParameter();
    }

    public String getServletPath() {
        return servletPath;
    }

    public void setServletPath(String servletPath) {
        this.servletPath = servletPath;
    }

    /**
     * 需要区分请求类型,get or post, request param 在不同的位置
     */
    private void parseRequest(){
        try{
            this.getRequestInfo();
            String[] requestInfoArray = requestInfo.split(CRLF);
            //请求头第一行GET(POST) uri?param HTTP/1.0
            String[] fristLine = requestInfoArray[0].split(BLANK);
            method = fristLine[0];
            //GET 请求
            if(method.equalsIgnoreCase("GET")){
                //判断是否携带参数
                String uri = fristLine[1];
                int idx = uri.indexOf("?");
                if(idx > -1){
                    this.setServletPath(uri.substring(0, idx));
                    paramStr = uri.substring(idx + 1, uri.length());
                    this.parseParameter();
                }else{
                    paramStr = "";
                    this.setServletPath(uri);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void parseParameter() {
        //the request param is as following:
        //GET /index.html?username=werwer&pass=werew&radioInput=1&radioInput=2 HTTP/1.1
        if(paramStr.length() > 0){
            parameterMap = new HashMap<>();
            try{
                paramStr = URLDecoder.decode(paramStr,characterEncoding);
                String[] keyValue = paramStr.split("&");

                for(String tmp : keyValue){
                    String[] kV = tmp.split("=");

                    if(!parameterMap.containsKey(kV[0])){
                        parameterMap.put(kV[0], new ArrayList<>());
                    }
                    List<String> values = parameterMap.get(kV[0]);
                    //TODO kV可能存在没有值的情况
                    if(kV.length == 1){
                        //数组扩容
                        kV = Arrays.copyOf(kV, 2);
                        kV[1] = null;
                    }
                    values.add(kV[1]);
                }
            }catch (UnsupportedEncodingException e){
                e.printStackTrace();
            }
        }
    }

    private void getRequestInfo() throws IOException{
        StringBuilder str = new StringBuilder();
        byte[] bs = new byte[1024];
        int len = 0;
        while((len = inputStream.read(bs)) != -1){
            str.append(new String(bs, 0 ,len));
            //表示已经读到结尾,防止堵塞
            //TODO 正好读到1024结束,1024表示最大存储字节,可能会出现没有1024字节,但是还没有读完的情况
            if(len < 1024){
                break;
            }
        }
        requestInfo = str.toString();
    }

    public void setParameterMap(Map<String, List<String>> parameterMap) {
        this.parameterMap = parameterMap;
    }

    public Map<String, List<String>> getParameterMap(){
        return parameterMap;
    }

    public String getParameter(String key){
        if(parameterMap.containsKey(key)){
            List<String> values = parameterMap.get(key);
            return values.get(0);
        }
        return null;
    }

    public Set<String> getParameterNames(){
        return parameterMap.keySet();
    }

    public String[] getParameterValues(String key){
        List<String> values = null;
        if(!parameterMap.containsKey(key)){
            return null;
        }
        //参数是为了返回String[]
        return values.toArray(new String[0]);
    }
}
